import {useEffect, useRef, useState} from 'react'
import {CharacterSoldier} from './CharacterSoldier.jsx'
import {CapsuleCollider, RigidBody, vec3} from '@react-three/rapier'
import {useFrame, useThree} from '@react-three/fiber'
import {isHost} from 'playroomkit'
import {Billboard, CameraControls, Text} from '@react-three/drei'

// 玩家移动速度
const MOVE_SPEED = 202
// 子弹间隔
const FIRE_RATE = 380

export const WEAPON_OFFSET = {
  x: -0.2,
  y: 1.4,
  z: 0.8
}

export const CharacterController = (
  {
    state,
    joystick,
    userPlayer,
    onFire,
    onKilled,
    ...props
  }
) => {

  const groupRef = useRef()
  const rigidBodyRef = useRef()
  const characterRef = useRef()
  const controlsRef = useRef()

  // 上次射击时间
  const lastShoot = useRef(0)

  const [animation, setAnimation] = useState('Idle')
  const scene = useThree((state) => state.scene)

  useFrame((_, delta) => {
    if (!rigidBodyRef.current) return

    // 相机跟随人物移动实现
    if (controlsRef.current) {
      const y_distance = window.innerWidth < 1024 ? 16 : 20
      const z_distance = window.innerWidth < 1024 ? 12 : 16

      const playerPos = vec3(rigidBodyRef.current?.translation())
      controlsRef.current.setLookAt(
        playerPos.x,
        playerPos.y + (state.state.dead ? 12 : y_distance),
        playerPos.z + (state.state.dead ? 2 : z_distance),
        playerPos.x,
        playerPos.y + 1.5,
        playerPos.z,
        true
      )
    }

    if (state.state.dead) {
      setAnimation('Death')
      return
    }

    const angle = joystick.angle()

    if (joystick.isJoystickPressed() && angle) {
      setAnimation('Run')
      characterRef.current.rotation.y = angle

      // 使角色在自己的方向上移动
      const impulse = {
        x: Math.sin(angle) * MOVE_SPEED * delta,
        y: 0,
        z: Math.cos(angle) * MOVE_SPEED * delta
      }
      rigidBodyRef.current.applyImpulse(impulse, true)

    } else {
      setAnimation('Idle')
    }

    /* 玩家碰撞效果 */
    if (isHost()) {
      state.setState('pos', rigidBodyRef.current.translation())
    } else {
      const pos = state.getState('pos')
      if (pos) {
        rigidBodyRef.current?.setTranslation(pos)
      }
    }

    // 点击开火
    if (joystick.isPressed('fire')) {
      // 射击动画
      setAnimation('Idle_Shoot')

      console.log('-----isHost-', isHost())

      if (isHost()) {
        // 是否超过子弹开火间隔时间
        if (Date.now() - lastShoot.current > FIRE_RATE) {
          // 设置上次射击时间为当前时间
          lastShoot.current = Date.now()
          // 生成新的子弹
          const newBullet = {
            id: state.id + '-' + +new Date(),
            position: vec3(rigidBodyRef.current.translation()),
            angle,
            player: state.id
          }
          // 开火
          onFire(newBullet)
        }
      }
    }
  })

  // const onIntersectionEnterHandler =

  // 玩家死亡后重生效果
  const spawnRandomly = () => {
    const spawns = []
    for (let i = 0; i < 1000; i++) {
      const spawn = scene.getObjectByName(`spawn_${i}`)
      if (spawn) {
        spawns.push(spawn)
      } else {
        break
      }
    }
    const spawnPos = spawns[Math.floor(Math.random() * spawns.length)].position
    rigidBodyRef.current.setTranslation(spawnPos)
  }

  useEffect(() => {
    if (isHost()) {
      spawnRandomly()
    }
  }, [])

  return (
    <group ref={groupRef} {...props}>

      {/* 添加相机 */}
      {
        userPlayer &&
        (
          <CameraControls ref={controlsRef}/>
        )
      }

      <RigidBody
        ref={rigidBodyRef}
        colliders={false}
        linearDamping={12}
        lockRotations
        type={isHost() ? 'dynamic' : 'kinematicPosition'}
        onIntersectionEnter={({other}) => {
          console.log('newHealth--- into', isHost(), other.rigidBody.useData.type === 'bullet', state.state.health)
          if (
            isHost() &&
            other.rigidBody.useData.type === 'bullet' &&
            state.state.health > 0
          ) {
            const newHealth =
              state.state.health - other.rigidBody.useData.damage
            console.log('newHealth---', newHealth)
            if (newHealth <= 0) {
              state.setState('deaths', state.state.deaths + 1)
              state.setState('dead', true)
              state.setState('health', 0)
              rigidBodyRef.current.setEnabled(false)
              setTimeout(() => {
                spawnRandomly()
                rigidBodyRef.current.setEnabled(true)
                state.setState('health', 100)
                state.setState('dead', false)
              }, 2000)
              onKilled(state.id, other.rigidBody.userData.player)
            } else {
              console.log('newHealth---', newHealth)
              state.setState('health', newHealth)
            }
          }
        }}
      >
        <PlayerInfo state={state.state}/>
        <group ref={characterRef}>
          <CharacterSoldier
            color={state.state.profile?.color}
            animation={animation}
          />
          {
            userPlayer &&
            <Crosshair
              position={[WEAPON_OFFSET.x, WEAPON_OFFSET.y, WEAPON_OFFSET.z]}
            />
          }
        </group>
        <CapsuleCollider args={[0.7, 0.6]} position={[0, 1.28, 0]}/>
      </RigidBody>
    </group>
  )
}

/* 玩家名称和血条 */
const PlayerInfo = ({state}) => {
  const health = state.health
  const name = state.profile.name
  return (
    <Billboard position-y={2.5}>
      <Text position-y={0.36} fontSize={0.4}>
        {name}
        <meshBasicMaterial color={state.profile.color}/>
      </Text>
      <mesh position-z={-0.1}>
        <planeGeometry args={[1, 0.2]}/>
        <meshBasicMaterial color="black" transparent opacity={0.5}/>
      </mesh>
      <mesh scale-x={health / 100} position-x={-0.5 * (1 - health / 100)}>
        <planeGeometry args={[1, 0.2]}/>
        <meshBasicMaterial color="red"/>
      </mesh>
    </Billboard>
  )
}

/* 瞄准虚线 */
const Crosshair = (props) => {
  return (
    <group {...props}>
      <mesh position-z={1}>
        <boxGeometry args={[0.05, 0.05, 0.05]}/>
        <meshBasicMaterial color="black" transparent opacity={0.9}/>
      </mesh>
      <mesh position-z={2}>
        <boxGeometry args={[0.05, 0.05, 0.05]}/>
        <meshBasicMaterial color="black" transparent opacity={0.85}/>
      </mesh>
      <mesh position-z={3}>
        <boxGeometry args={[0.05, 0.05, 0.05]}/>
        <meshBasicMaterial color="black" transparent opacity={0.8}/>
      </mesh>

      <mesh position-z={4.5}>
        <boxGeometry args={[0.05, 0.05, 0.05]}/>
        <meshBasicMaterial color="black" opacity={0.7} transparent/>
      </mesh>

      <mesh position-z={6.5}>
        <boxGeometry args={[0.05, 0.05, 0.05]}/>
        <meshBasicMaterial color="black" opacity={0.6} transparent/>
      </mesh>

      <mesh position-z={9}>
        <boxGeometry args={[0.05, 0.05, 0.05]}/>
        <meshBasicMaterial color="black" opacity={0.2} transparent/>
      </mesh>
    </group>
  )
}
